﻿using Abp.Dependency;
using Abp.Extensions;
using Abp.Runtime.Caching;
using DHJ.Cost.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DHJ.Cost.CostAccounting.Cache
{
    public class BatchCostCache : ISingletonDependency, IBatchCostCache
    {

        private readonly ICacheManager _cacheManager;
        private readonly IBatchManager _batchManager;
        private readonly IBatchCostManager _batchCostManager;


        public BatchCostCache(ICacheManager cacheManager, IBatchManager batchManager, IBatchCostManager batchCostManager)
        {
            _cacheManager = cacheManager;
            _batchManager = batchManager;
            _batchCostManager = batchCostManager;
        }

        public async Task<BatchCostDetailCacheItem> GetDetailCacheItemOrNull(string id)
        {
            return await _cacheManager
                .GetCache(BatchCostDetailCacheItem.CacheName)
                .GetOrDefaultAsync(id) as BatchCostDetailCacheItem;
        }

        public async Task<BatchCostCacheItem> GetCacheItemOrNull(string id)
        {
            return await _cacheManager
                .GetCache(BatchCostCacheItem.CacheName)
                .GetOrDefaultAsync(id) as BatchCostCacheItem;
        }

        /// <summary>
        /// 清空 items
        /// </summary>
        /// <returns></returns>
        public async System.Threading.Tasks.Task ClearDetailCache()
        {
            await _cacheManager
                .GetCache(BatchCostDetailCacheItem.CacheName).ClearAsync();
        }

        /// <summary>
        /// 清空 items
        /// </summary>
        /// <returns></returns>
        public async System.Threading.Tasks.Task ClearCache()
        {
            await _cacheManager
                .GetCache(BatchCostCacheItem.CacheName).ClearAsync();
        }


        /// <summary>
        /// 初始化 items
        /// </summary>
        /// <returns></returns>
        public async System.Threading.Tasks.Task InitDetailCache()
        {

            var i = 0;
            await ClearDetailCache();

            var batches = _batchManager.Batches()
                           .Where(e => e.Quantity > 0)
                 .Select(e => new BatchIdentifier(e.Id, e.Quantity)).ToList();

            var items = new List<BatchCostDetailCacheItem>();

            foreach (var batch in batches)
            {
                var costs = _batchCostManager.GetCosts(batch).Select(e => new BatchCostDetailCacheItem
                {
                    Id = e.Id,
                    BatchId = e.BatchId,
                    Quantity = e.Quantity,
                    Workshop = e.Workshop,
                    Ratio = e.Ratio,
                    Time = e.ActualCost.Time,
                    Category = e.ActualCost.Detail.Category,
                    Title = e.ActualCost.Detail.Title,
                    Amount = e.ActualCost.Detail.Amount,
                    UnitCost = e.ActualCost.Detail.Amount * e.Ratio / e.Quantity,
                    AssemQuantity = batch.Quantity
                });

                items.AddRange(costs);
                i++;
            }

            var cache = _cacheManager.GetCache(BatchCostDetailCacheItem.CacheName);

            cache.DefaultSlidingExpireTime = TimeSpan.FromDays(90);

            await cache.SetAsync("keys", items.Select(e => e.Id).ToList());

            foreach (var item in items)
            {
                await cache.SetAsync(item.Id.ToString(), item);
            }
        }

        /// <summary>
        /// 初始化 items
        /// </summary>
        /// <returns></returns>
        public async System.Threading.Tasks.Task InitCache()
        {
            await ClearCache();

            var batches = await GetDetailCacheItems();

            var items = batches.GroupBy(e => new { e.BatchId, e.Quantity, e.Category, e.Workshop })
                .Select(g => new BatchCostCacheItem
                {
                    Id = Guid.NewGuid(),
                    BatchId = g.Key.BatchId,
                    Quantity = g.Key.Quantity,
                    Category = g.Key.Category,
                    Workshop = g.Key.Workshop,
                    Cost = g.Sum(e => e.UnitCost * g.Key.Quantity)
                }).ToList();

            var cache = _cacheManager.GetCache(BatchCostCacheItem.CacheName);

            cache.DefaultSlidingExpireTime = TimeSpan.FromDays(90);

            await cache.SetAsync("keys", items.Select(e => e.Id).ToList());

            foreach (var item in items)
            {
                await cache.SetAsync(item.Id.ToString(), item);
            }
        }

        /// <summary>
        /// 获得所有的 items
        /// </summary>
        /// <returns></returns>
        public async Task<List<BatchCostDetailCacheItem>> GetDetailCacheItems()
        {
            var cache = _cacheManager.GetCache(BatchCostDetailCacheItem.CacheName);

            var keys = await cache
                .GetOrDefaultAsync("keys") as List<Guid>; ;

            if (keys == null || keys.Count == 0)
                return new List<BatchCostDetailCacheItem>();

            var items = keys.Select(key => cache.Get(key, () => new BatchCostDetailCacheItem()
            {
                Id = Guid.Empty
            })).Where(e => e.Id != Guid.Empty).ToList();


            if (items == null || items.Count == 0)
            {
                items = new List<BatchCostDetailCacheItem>();
            }

            return items;
        }

        /// <summary>
        /// 获得所有的 items
        /// </summary>
        /// <returns></returns>
        public async Task<List<BatchCostCacheItem>> GetCacheItems()
        {
            var cache = _cacheManager.GetCache(BatchCostCacheItem.CacheName);

            var keys = await cache
                .GetOrDefaultAsync("keys") as List<Guid>; ;

            if (keys == null || keys.Count == 0)
                return new List<BatchCostCacheItem>();

            var items = keys.Select(key => cache.Get(key, () => new BatchCostCacheItem()
            {
                Id = Guid.Empty
            })).Where(e => e.Id != Guid.Empty).ToList();

            if (items == null || items.Count == 0)
            {
                items = new List<BatchCostCacheItem>();
            }

            return items;
        }
    }
}
